/**
 * @author hfutrell
 */

var table = [
	[ 0, 0, 0],
	[ 255, 0, 0],
	[ 255, 255, 0],
	[ 0, 255, 0],
	[ 0, 255, 255],
	[ 0, 0, 255],
	[ 255, 0, 255],
	[ 255, 255, 255],
	[ 65, 65, 65],
	[ 128, 128, 128],
	[ 255, 0, 0],
	[ 255, 170, 170],
	[ 189, 0, 0],
	[ 189, 126, 126],
	[ 129, 0, 0],
	[ 129, 86, 86],
	[ 104, 0, 0],
	[ 104, 69, 69],
	[ 79, 0, 0],
	[ 79, 53, 53],
	[ 255, 63, 0],
	[ 255, 191, 170],
	[ 189, 46, 0],
	[ 189, 141, 126],
	[ 129, 31, 0],
	[ 129, 96, 86],
	[ 104, 25, 0],
	[ 104, 78, 69],
	[ 79, 19, 0],
	[ 79, 59, 53],
	[ 255, 127, 0],
	[ 255, 212, 170],
	[ 189, 94, 0],
	[ 189, 157, 126],
	[ 129, 64, 0],
	[ 129, 107, 86],
	[ 104, 52, 0],
	[ 104, 86, 69],
	[ 79, 39, 0],
	[ 79, 66, 53],
	[ 255, 191, 0],
	[ 255, 234, 170],
	[ 189, 141, 0],
	[ 189, 173, 126],
	[ 129, 96, 0],
	[ 129, 118, 86],
	[ 104, 78, 0],
	[ 104, 95, 69],
	[ 79, 59, 0],
	[ 79, 73, 53],
	[ 255, 255, 0],
	[ 255, 255, 170],
	[ 189, 189, 0],
	[ 189, 189, 126],
	[ 129, 129, 0],
	[ 129, 129, 86],
	[ 104, 104, 0],
	[ 104, 104, 69],
	[ 79, 79, 0],
	[ 79, 79, 53],
	[ 191, 255, 0],
	[ 234, 255, 170],
	[ 141, 189, 0],
	[ 173, 189, 126],
	[ 96, 129, 0],
	[ 118, 129, 86],
	[ 78, 104, 0],
	[ 95, 104, 69],
	[ 59, 79, 0],
	[ 73, 79, 53],
	[ 127, 255, 0],
	[ 212, 255, 170],
	[ 94, 189, 0],
	[ 157, 189, 126],
	[ 64, 129, 0],
	[ 107, 129, 86],
	[ 52, 104, 0],
	[ 86, 104, 69],
	[ 39, 79, 0],
	[ 66, 79, 53],
	[ 63, 255, 0],
	[ 191, 255, 170],
	[ 46, 189, 0],
	[ 141, 189, 126],
	[ 31, 129, 0],
	[ 96, 129, 86],
	[ 25, 104, 0],
	[ 78, 104, 69],
	[ 19, 79, 0],
	[ 59, 79, 53],
	[ 0, 255, 0],
	[ 170, 255, 170],
	[ 0, 189, 0],
	[ 126, 189, 126],
	[ 0, 129, 0],
	[ 86, 129, 86],
	[ 0, 104, 0],
	[ 69, 104, 69],
	[ 0, 79, 0],
	[ 53, 79, 53],
	[ 0, 255, 63],
	[ 170, 255, 191],
	[ 0, 189, 46],
	[ 126, 189, 141],
	[ 0, 129, 31],
	[ 86, 129, 96],
	[ 0, 104, 25],
	[ 69, 104, 78],
	[ 0, 79, 19],
	[ 53, 79, 59],
	[ 0, 255, 127],
	[ 170, 255, 212],
	[ 0, 189, 94],
	[ 126, 189, 157],
	[ 0, 129, 64],
	[ 86, 129, 107],
	[ 0, 104, 52],
	[ 69, 104, 86],
	[ 0, 79, 39],
	[ 53, 79, 66],
	[ 0, 255, 191],
	[ 170, 255, 234],
	[ 0, 189, 141],
	[ 126, 189, 173],
	[ 0, 129, 96],
	[ 86, 129, 118],
	[ 0, 104, 78],
	[ 69, 104, 95],
	[ 0, 79, 59],
	[ 53, 79, 73],
	[ 0, 255, 255],
	[ 170, 255, 255],
	[ 0, 189, 189],
	[ 126, 189, 189],
	[ 0, 129, 129],
	[ 86, 129, 129],
	[ 0, 104, 104],
	[ 69, 104, 104],
	[ 0, 79, 79],
	[ 53, 79, 79],
	[ 0, 191, 255],
	[ 170, 234, 255],
	[ 0, 141, 189],
	[ 126, 173, 189],
	[ 0, 96, 129],
	[ 86, 118, 129],
	[ 0, 78, 104],
	[ 69, 95, 104],
	[ 0, 59, 79],
	[ 53, 73, 79],
	[ 0, 127, 255],
	[ 170, 212, 255],
	[ 0, 94, 189],
	[ 126, 157, 189],
	[ 0, 64, 129],
	[ 86, 107, 129],
	[ 0, 52, 104],
	[ 69, 86, 104],
	[ 0, 39, 79],
	[ 53, 66, 79],
	[ 0, 63, 255],
	[ 170, 191, 255],
	[ 0, 46, 189],
	[ 126, 141, 189],
	[ 0, 31, 129],
	[ 86, 96, 129],
	[ 0, 25, 104],
	[ 69, 78, 104],
	[ 0, 19, 79],
	[ 53, 59, 79],
	[ 0, 0, 255],
	[ 170, 170, 255],
	[ 0, 0, 189],
	[ 126, 126, 189],
	[ 0, 0, 129],
	[ 86, 86, 129],
	[ 0, 0, 104],
	[ 69, 69, 104],
	[ 0, 0, 79],
	[ 53, 53, 79],
	[ 63, 0, 255],
	[ 191, 170, 255],
	[ 46, 0, 189],
	[ 141, 126, 189],
	[ 31, 0, 129],
	[ 96, 86, 129],
	[ 25, 0, 104],
	[ 78, 69, 104],
	[ 19, 0, 79],
	[ 59, 53, 79],
	[ 127, 0, 255],
	[ 212, 170, 255],
	[ 94, 0, 189],
	[ 157, 126, 189],
	[ 64, 0, 129],
	[ 107, 86, 129],
	[ 52, 0, 104],
	[ 86, 69, 104],
	[ 39, 0, 79],
	[ 66, 53, 79],
	[ 191, 0, 255],
	[ 234, 170, 255],
	[ 141, 0, 189],
	[ 173, 126, 189],
	[ 96, 0, 129],
	[ 118, 86, 129],
	[ 78, 0, 104],
	[ 95, 69, 104],
	[ 59, 0, 79],
	[ 73, 53, 79],
	[ 255, 0, 255],
	[ 255, 170, 255],
	[ 189, 0, 189],
	[ 189, 126, 189],
	[ 129, 0, 129],
	[ 129, 86, 129],
	[ 104, 0, 104],
	[ 104, 69, 104],
	[ 79, 0, 79],
	[ 79, 53, 79],
	[ 255, 0, 191],
	[ 255, 170, 234],
	[ 189, 0, 141],
	[ 189, 126, 173],
	[ 129, 0, 96],
	[ 129, 86, 118],
	[ 104, 0, 78],
	[ 104, 69, 95],
	[ 79, 0, 59],
	[ 79, 53, 73],
	[ 255, 0, 127],
	[ 255, 170, 212],
	[ 189, 0, 94],
	[ 189, 126, 157],
	[ 129, 0, 64],
	[ 129, 86, 107],
	[ 104, 0, 52],
	[ 104, 69, 86],
	[ 79, 0, 39],
	[ 79, 53, 66],
	[ 255, 0, 63],
	[ 255, 170, 191],
	[ 189, 0, 46],
	[ 189, 126, 141],
	[ 129, 0, 31],
	[ 129, 86, 96],
	[ 104, 0, 25],
	[ 104, 69, 78],
	[ 79, 0, 19],
	[ 79, 53, 59],
	[ 51, 51, 51],
	[ 80, 80, 80],
	[ 105, 105, 105],
	[ 130, 130, 130],
	[ 190, 190, 190],
	[ 255, 255, 255]
];

function getColor(index){
	if (index >= 0 && index <= 255) {
		var color = table[index];
		if ( color[0] === 255 && color[1] === 255 && color[2] === 255) {
			color = [0,0,0];
		}
		return color;
	}
	return [ 0, 0, 0 ];

}

function Wireframe() {
 	this.lineData = [];
	this.colorData = [];
	this.lineBuffer = null;
	this.colorBuffer = null;
	this.numLines = 0;
}

Wireframe.prototype.lineData = null;
Wireframe.prototype.colorData = null;
Wireframe.prototype.lineBuffer = null;
Wireframe.prototype.colorBuffer = null;
Wireframe.prototype.numLines = 0;

Wireframe.prototype.addLine = function(startx, starty, endx, endy, color) {
 	this.lineData.push(startx);
	this.lineData.push(starty);
 	this.lineData.push(endx);
 	this.lineData.push(endy);
	this.colorData.push(color[0] / 255.0);
	this.colorData.push(color[1] / 255.0);
	this.colorData.push(color[2] / 255.0);
	this.colorData.push(1.0);
	this.colorData.push(color[0] / 255.0);
	this.colorData.push(color[1] / 255.0);
	this.colorData.push(color[2] / 255.0);
	this.colorData.push(1.0);
	this.numLines++;
};

Wireframe.transform = function(x, M) {
	
	if ( M === null ) return x;

	var vector = $V(x.concat([0, 1]));
	var result = M.multiply(vector);
	result.multiply(1.0 / result.e(4));
	return result.elements;
	
};

Wireframe.OCSToWCS = function(node, x, t) {
	if (node.childExistsForCode(210)) {
		var z = node.childOfCode(230).doubleValue();
		if ( z < 0.0 ) {
			x[0] = -x[0];
		}
	}
	return Wireframe.transform(x, t);
};

Wireframe.getAndTransform = function(node, code1, code2, t, isOCS) {
	if ( node.childExistsForCode(code1) && node.childExistsForCode(code2 ) ) {
		var x = node.childOfCode(code1).doubleValue();
		var y = node.childOfCode(code2).doubleValue();
		if ( isOCS === true ) {
			if (node.childExistsForCode(210) && node.childOfCode(210).intValue === 1) {
				var z = node.childOfCode(230).doubleValue();
				if ( z < 0.0 ) {
					x = -x;
				}
			}
		}
		return Wireframe.transform([x, y], t);
	}
	else {
		console.warning("node did not have propre codes");
	}
};

Wireframe.prototype.addNode = function(node, parser, t) {
	
	var byLayer = false;
	var byBlock = false;
	var color = [0,0,0];
	
	if (node.code !== 0) {
		return;
	}
	
	if (node.childExistsForCode(67) && node.childOfCode(67).intValue() === 1) {
		return;
	}
		
	if ( node.childExistsForCode(60)) {
		if (node.childOfCode(60).intValue() === 0) {
			// object marked not visible
			return;
		}
	}
	
	if ( node.childExistsForCode(62)) {
		var index = node.childOfCode(62).intValue();
		if (index === 0) {
			byBlock = true;
		}
		else if ( index === 256 ) {
			byLayer = true;
		}
		else {
			// lookup colors from table
			color = getColor(index);
		}
	}
	else {
		byLayer = true;
	}
	
	if ( byLayer && node.childExistsForCode(8)) {
		var layerName = node.childOfCode(8).stringValue();
		var layer = parser.getLayer(layerName);
		if ( layer ) {
			if (layer.childExistsForCode(62)) {
				var layerColorIndex = layer.childOfCode(62).intValue();
				if ( layerColorIndex < 0 ) {
					return;
				}
				else {
					// lookup colors
					color = getColor(layerColorIndex);
				}
			}
		}
	}
	
	var x0, x1; // tuples to hold line coordinates
	var r;
	var iterations;
	var i;
	var c; // center
	var child;
	
        if (node.stringValue() === "LINE") {
			x0 = Wireframe.getAndTransform(node, 10, 20, t, false);
			x1 = Wireframe.getAndTransform(node, 11, 21, t, false);
            this.addLine(x0[0], x0[1], x1[0], x1[1], color);
        }
		else if (node.stringValue() === "CIRCLE") {
			c = [node.childOfCode(10).doubleValue(), node.childOfCode(20).doubleValue()];
			r = node.childOfCode(40).doubleValue();
			iterations = 20;
			x0 = null;
			for (i=0; i<=iterations; i++) {
				var theta = i * (Math.PI * 2.0 / iterations);
				x1 = [ c[0] + r * Math.cos(theta), c[1] + r * Math.sin(theta) ];
				x1 = Wireframe.OCSToWCS(node, x1, t);
				if (i !== 0) {
					this.addLine(x0[0], x0[1], x1[0], x1[1], color);
				}
				x0 = x1;
			}
		}
		else if (node.stringValue() === "ARC") {
			c = [node.childOfCode(10).doubleValue(), node.childOfCode(20).doubleValue()];
			r = node.childOfCode(40).doubleValue();
			iterations = 10;
			
			var startTheta 	= node.childOfCode(50).doubleValue() * Math.PI / 180.0;
			var endTheta	= node.childOfCode(51).doubleValue() * Math.PI / 180.0;
			var dTheta 		= endTheta - startTheta;
			if ( endTheta < startTheta ) {
				dTheta += 2.0 * Math.PI;
			}
		
			x0 = null;
			for (i=0; i<=iterations; i++) {
				var theta1 = i * (dTheta / iterations) + startTheta;
				x1 = [ c[0] + r * Math.cos(theta1), c[1] + r * Math.sin(theta1) ];
				x1 = Wireframe.OCSToWCS(node, x1, t);
				if ( i !== 0 ) {
					this.addLine(x0[0], x0[1], x1[0], x1[1], color);
				}
				x0 = x1;
			}

		}
		else if (node.stringValue() === "SOLID") {
			var s1 = Wireframe.getAndTransform(node, 10, 20, t, false);
			var s2 = Wireframe.getAndTransform(node, 11, 21, t, false);
			var s3 = Wireframe.getAndTransform(node, 12, 22, t, false);
			var s4 = Wireframe.getAndTransform(node, 13, 23, t, false);
			this.addLine(s1[0], s1[1], s2[0], s2[1], color);
			this.addLine(s2[0], s2[1], s3[0], s3[1], color);
			this.addLine(s3[0], s3[1], s4[0], s4[1], color);
			this.addLine(s4[0], s4[1], s1[0], s1[1], color);
		}
		else if (node.stringValue() === "SPLINE") {
			;
		}
		else 
			if (node.stringValue() === "POLYLINE") {
			
				var closed = false;
				if (node.childExistsForCode(70)) {
					var flags = node.childOfCode(70).intValue();
					if (flags & 1) {
						closed = true;
					}
					if (flags & 2) {
						console.log("Curve fit vertices added");
					}
					if (flags & 4) {
						console.log("Spline fit vertices added");
					}
				}
				if (node.childExistsForCode(75)) {
					var curveType = node.childOfCode(75).intValue();
					if (curveType == 0) {
						console.log("No Smoothing");
					}
					if (curveType == 5) {
						console.log("Curve Quadratic B-Spline");
					}
					if (curveType == 6) {
						console.log("Cubic Quadratic B-Spline");
					}
					if (curveType == 8) {
						console.log("Bezier Surface");
					}
				}
				
				
				var segments = [];
				
				for (i = 0; i < node.children.length; i++) {
					child = node.children[i];
					if (child.code === 0 && child.stringValue() === "VERTEX") {
						segments.push(Wireframe.getAndTransform(child, 10, 20, t, true));
					}
				}
				for (i = 0; i < segments.length - 1; i++) {
					this.addLine(segments[i][0], segments[i][1], segments[i + 1][0], segments[i + 1][1], color);
				}
				if (closed && segments.length > 2) {
					this.addLine(segments[segments.length - 1][0], segments[segments.length - 1][1], segments[0][0], segments[0][1], color);
				}
			}
			else if (node.stringValue() === "ELLIPSE") {
				console.warn("handling ellipse!");
			}
			else if (node.stringValue() === "INSERT") {
				var blockName = node.childOfCode(2).stringValue();
				var block = parser.getBlock(blockName);
				if (block) {
					var u = Matrix.I(4);
					if (node.childExistsForCode(41)) {
						u.elements[0][0] = node.childOfCode(41).doubleValue();
					}
					if (node.childExistsForCode(42)) {
						u.elements[1][1] = node.childOfCode(42).doubleValue();
					}
					if (node.childExistsForCode(50)) {
						var angle = node.childOfCode(50).doubleValue();
						var m = Matrix.RotationZ(angle * Math.PI / 180.0).ensure4x4();
						u = m.multiply(u);
					}
					if (node.childExistsForCode(10) && node.childExistsForCode(20)) {
						var tx = node.childOfCode(10).doubleValue();
						var ty = node.childOfCode(20).doubleValue();
						u = Matrix.Translation($V([tx, ty, 0])).ensure4x4().multiply(u);
					}
					var newTransform = t === null ? u : t.multiply(u);
					for (i = 0; i < block.children.length; i++) {
						child = block.children[i];
						this.addNode(child, parser, newTransform);
					}
				}
			}
};


Wireframe.prototype.build = function(parser) {

						
	var rootEntity = parser.rootEntity;
			
	var startTime = (new Date).getTime();
	var i;
					
	for(i=0; i<rootEntity.children.length; i++) {
		this.addNode(rootEntity.children[i], parser, null );
	}

	var endTime = (new Date).getTime();
	var diff = endTime - startTime;
		
	console.log("took " + diff + "ms to build DXF");


	this.lineBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, this.lineBuffer );
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.lineData), gl.STATIC_DRAW);
	
	this.colorBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer );
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.colorData), gl.STATIC_DRAW);

	
	rb_check_error("build wireframe");

};

Wireframe.prototype.draw = function(vertexLocation, colorLocation) {
 
 	gl.bindBuffer(gl.ARRAY_BUFFER, this.lineBuffer );
	gl.vertexAttribPointer( vertexLocation, 2, gl.FLOAT, false, 0, 0);
	gl.enableVertexAttribArray( vertexLocation );
	
	gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer );
	gl.vertexAttribPointer( colorLocation, 4, gl.FLOAT, false, 0, 0);
	gl.enableVertexAttribArray( colorLocation );

	
 	gl.drawArrays(gl.LINES, 0, 2 * this.numLines );
	
	rb_check_error("draw wireframe");
	
	gl.disableVertexAttribArray( vertexLocation );
	gl.disableVertexAttribArray( colorLocation );

	
};
 
 
